package com.ruoyi.algorithm.util;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * @author ：yanfa-03
 * @date ：Created in 2021/7/12/14:36
 * @description ：反射工具
 * @version: 1.0
 */
public class ReflectionUtil {
    /**
     * 获取某包下（包括该包的所有子包）所有类
     *
     * @param packageName 包名
     * @return 类的完整名称
     */
    public static List<String> getClassName(String packageName) {
        return getClassName(packageName, true);
    }

    /**
     * 获取某包下所有类
     *
     * @param packageName  包名
     * @param childPackage 是否遍历子包
     * @return 类的完整名称
     */
    public static List<String> getClassName(String packageName, boolean childPackage) {
        List<String> fileNames = null;
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        String packagePath = packageName.replace(".", "/");
        URL url = loader.getResource(packagePath);
        if (url != null) {
            String type = url.getProtocol();
            if (type.equals("file")) {
                fileNames = getClassNameByFile(url.getPath(), null, childPackage);
            }
        }
        return fileNames;
    }

    /**
     * 从项目文件获取某包下所有类
     *
     * @param filePath     文件路径
     * @param className    类名集合
     * @param childPackage 是否遍历子包
     * @return 类的完整名称
     */
    private static List<String> getClassNameByFile(String filePath, List<String> className, boolean childPackage) {
        List<String> myClassName = new ArrayList<String>();
        File file = new File(filePath);
        File[] childFiles = file.listFiles();
        if (childFiles != null) {
            for (File childFile : childFiles) {
                if (childFile.isDirectory()) {
                    if (childPackage) {
                        myClassName.addAll(getClassNameByFile(childFile.getPath(), myClassName, childPackage));
                    }
                } else {
                    String childFilePath = childFile.getPath();
                    if (childFilePath.endsWith(".class")) {
                        childFilePath = childFilePath.substring(childFilePath.indexOf(File.separator + "classes") + 9, childFilePath.lastIndexOf("."));
                        childFilePath = childFilePath.replace(File.separator, ".");
                        myClassName.add(childFilePath);
                    }
                }
            }
        }
        return myClassName;
    }

    /**
     * 通过属性字段名获取到对应的数据库字段名
     *
     * @param aClass 对象
     * @param field  字段
     * @return
     */
    public static String getTableFieldValue(Class aClass, String field) {
        if (StringUtils.isBlank(field)){
            return null;
        }
        try {
            Field declaredField = aClass.getDeclaredField(field);
            TableField annotation = declaredField.getAnnotation(TableField.class);
            if (null == annotation) {
                return camelToUnderline(field, 1);
            }
            String value = annotation.value();
            return value;
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 通过属性字段名获取到对应的数据库字段名
     *
     * @param classes 该列表添加带有查询条件专用注解的类，如有继承关系可单独添加子类
     * @param field      字段
     * @return '实体类字段'对应'表字段'名(如添加多个继承关系类，只返回最先匹配到的字段名)
     */
    public static String getTableFieldValue(List<Class<?>> classes, String field) {
        if (StringUtils.checkValNull(field)) {
            return null;
        }
        for (Class<?> aClass : classes) {
            String annotation = getField(field, aClass);
            if (annotation != null) {
                return annotation;
            }
        }
        return null;
    }

    private static String getField(String field, Class<?> clazz) {
        Field declaredField = null;
        try {
            declaredField = clazz.getDeclaredField(field);
        } catch (NoSuchFieldException e) {
            Class<?> superclass = clazz.getSuperclass();
            if (superclass == null) {
                return null;
            }
            return getField(field, superclass);
        }
        TableField annotation = declaredField.getAnnotation(TableField.class);
        if (null == annotation) {
            throw new RuntimeException("该字段不提供查询或排序作为条件");
        }
        return annotation.value();
    }

    //驼峰转下划线
    public static String camelToUnderline(String param, Integer charType) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append("_");
            }
            if (charType == 2) {
                sb.append(Character.toUpperCase(c));  //统一都转大写
            } else {
                sb.append(Character.toLowerCase(c));  //统一都转小写
            }
        }
        return sb.toString();
    }


    /**
     * 根据注解，驼峰转下划线（单表）
     *
     * @param orderBy 排序根据字段（驼峰）
     * @param aClass  排序字段对应表实例class对象
     * @return 排序根据字段数组（下划线）
     * @throws NoSuchFieldException 没有该字段
     */
    public static String[] getTableField(String orderBy, Class<?> aClass) throws NoSuchFieldException {
        String[] orderByVar = new String[1];
        if (StringUtils.checkValNotNull(orderBy)) {
            Field declaredField = aClass.getDeclaredField(orderBy);
            TableField tableField = declaredField.getDeclaredAnnotation(TableField.class);
            orderByVar[0] = tableField.value();
        }
        return orderByVar;
    }

    /**
     * 获取本类，指定属性的匹配方式(like还是=)
     */
    public static String getTableFieldMatchType(Class<?> aClass, String field) {
        String condition = "";
        try {
            Field[] declaredFields = aClass.getDeclaredFields();

            Boolean isMatched = false;
            for (Field declaredField : declaredFields) {
                String fieldName = declaredField.getName();
                if (fieldName.equals(field)) {
                    TableField matchType = declaredField.getAnnotation(TableField.class);
                    if (matchType != null) {
                        condition = matchType.condition();
                    }
                    isMatched = true;
                }
            }

            if (!isMatched) {
                Class<?> superclass = aClass.getSuperclass();
                if (superclass == null) {
                    return condition;
                }
                return getTableFieldMatchType(superclass, field);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return condition;
    }
}
